---
title: "类和结构体 - 面向对象编程、属性和方法"
description: "学习 Swift 类和结构体：面向对象编程基础、属性、方法、构造函数，与 JavaScript 对比"
---

# 类和结构体：面向对象编程、属性和方法

在本模块中，我们将探索 Swift 中的面向对象编程（OOP），并与 JavaScript 的类和原型系统进行对比。Swift 提供了类（引用类型）和结构体（值类型），每种都有其特定的用例和特性。

## 目录
- [介绍：类与结构体](#介绍类与结构体)
- [声明类和结构体](#声明类和结构体)
- [属性](#属性)
- [方法](#方法)
- [初始化器（构造函数）](#初始化器构造函数)
- [继承和多态](#继承和多态)
- [值类型与引用类型](#值类型与引用类型)
- [协议（接口）](#协议接口)
- [高级特性](#高级特性)
- [练习题](#练习题)
- [关键要点](#关键要点)

## 介绍：类与结构体

- **类**：引用类型，支持继承、析构器、身份比较、引用语义。
- **结构体**：值类型，不支持继承，赋值时复制，值语义，轻量级，适合简单数据模型。

| 特性           | JavaScript 类 | Swift 类 | Swift 结构体 |
|----------------|---------------|----------|--------------|
| 引用类型       | 是            | 是       | 否           |
| 值类型         | 否            | 否       | 是           |
| 继承           | 是            | 是       | 否           |
| 析构器         | 否            | 是       | 否           |
| 可变性         | 动态          | 受控     | 受控         |
| 协议           | 否（接口）    | 是       | 是           |
| 使用场景       | 所有 OOP      | OOP      | 数据模型、轻量级类型 |

## 声明类和结构体

<UniversalEditor title="类和结构体声明对比" compare={true}>
```javascript !! js
// JavaScript 类声明
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    greet() {
        console.log(`你好，我的名字是 ${this.name}，我 ${this.age} 岁。`);
    }
}

const alice = new Person("Alice", 30);
alice.greet(); // 你好，我的名字是 Alice，我 30 岁。

// JavaScript 对象字面量（类似结构体）
const point = { x: 3, y: 4 };
console.log(point.x, point.y);
```

```swift !! swift
// Swift 类声明
class Person {
    var name: String
    var age: Int

    // 初始化器
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }

    // 方法
    func greet() {
        print("你好，我的名字是 \(name)，我 \(age) 岁。")
    }
}

let alice = Person(name: "Alice", age: 30)
alice.greet() // 你好，我的名字是 Alice，我 30 岁。

// Swift 结构体声明
struct Point {
    var x: Int
    var y: Int
}

let point = Point(x: 3, y: 4)
print(point.x, point.y)
```
</UniversalEditor>

## 属性

Swift 支持存储属性、计算属性和属性观察器。JavaScript 的属性总是动态的。

<UniversalEditor title="属性对比" compare={true}>
```javascript !! js
// JavaScript 属性
class Rectangle {
    constructor(width, height) {
        this.width = width;
        this.height = height;
    }

    // 计算属性（getter）
    get area() {
        return this.width * this.height;
    }

    // 属性观察器（手动实现）
    set width(value) {
        this._width = value;
        console.log("宽度改为", value);
    }
    get width() {
        return this._width;
    }
}

const rect = new Rectangle(10, 5);
console.log(rect.area); // 50
rect.width = 20; // 宽度改为 20
```

```swift !! swift
// Swift 属性
struct Rectangle {
    var width: Double {
        didSet {
            print("宽度改为", width)
        }
    }
    var height: Double

    // 计算属性
    var area: Double {
        return width * height
    }
}

var rect = Rectangle(width: 10, height: 5)
print(rect.area) // 50
rect.width = 20 // 宽度改为 20
```
</UniversalEditor>

## 方法

JavaScript 和 Swift 都支持实例方法。Swift 还支持静态/类方法和结构体的可变方法。

<UniversalEditor title="方法对比" compare={true}>
```javascript !! js
// JavaScript 实例和静态方法
class Counter {
    constructor() {
        this.count = 0;
    }
    increment() {
        this.count++;
    }
    static description() {
        return "一个简单的计数器";
    }
}

const counter = new Counter();
counter.increment();
console.log(counter.count); // 1
console.log(Counter.description()); // 一个简单的计数器
```

```swift !! swift
// Swift 实例、静态和可变方法
struct Counter {
    var count = 0
    // 可变方法（用于结构体）
    mutating func increment() {
        count += 1
    }
    // 静态方法
    static func description() -> String {
        return "一个简单的计数器"
    }
}

var counter = Counter()
counter.increment()
print(counter.count) // 1
print(Counter.description()) // 一个简单的计数器
```
</UniversalEditor>

## 初始化器（构造函数）

Swift 使用 `init` 作为初始化器。结构体默认获得成员初始化器。

<UniversalEditor title="初始化器对比" compare={true}>
```javascript !! js
// JavaScript 构造函数
class User {
    constructor(username, email) {
        this.username = username;
        this.email = email;
    }
}
const user = new User("bob", "bob@example.com");

// 对象字面量
const config = { host: "localhost", port: 8080 };
```

```swift !! swift
// Swift 类初始化器
class User {
    var username: String
    var email: String
    init(username: String, email: String) {
        self.username = username
        self.email = email
    }
}
let user = User(username: "bob", email: "bob@example.com")

// Swift 结构体成员初始化器
struct Config {
    var host: String
    var port: Int
}
let config = Config(host: "localhost", port: 8080)
```
</UniversalEditor>

## 继承和多态

Swift 类支持单继承，而 JavaScript 类也支持单继承，但可以使用混入和组合。

### 基本继承

<UniversalEditor title="继承对比" compare={true}>
```javascript !! js
// JavaScript 继承
class Animal {
    constructor(name) {
        this.name = name;
    }
    speak() {
        console.log(`${this.name} 发出声音`);
    }
}

class Dog extends Animal {
    constructor(name, breed) {
        super(name);
        this.breed = breed;
    }
    speak() {
        console.log(`${this.name} 汪汪叫`);
    }
}

const dog = new Dog("Buddy", "金毛");
dog.speak(); // Buddy 汪汪叫
```

```swift !! swift
// Swift 继承
class Animal {
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    func speak() {
        print("\(name) 发出声音")
    }
}

class Dog: Animal {
    var breed: String
    
    init(name: String, breed: String) {
        self.breed = breed
        super.init(name: name)
    }
    
    override func speak() {
        print("\(name) 汪汪叫")
    }
}

let dog = Dog(name: "Buddy", breed: "金毛")
dog.speak() // Buddy 汪汪叫
```
</UniversalEditor>

### 多态

<UniversalEditor title="多态对比" compare={true}>
```javascript !! js
// JavaScript 多态
class Cat extends Animal {
    speak() {
        console.log(`${this.name} 喵喵叫`);
    }
}

function makeAnimalSpeak(animal) {
    animal.speak();
}

const animals = [
    new Dog("Buddy", "金毛"),
    new Cat("Whiskers")
];

animals.forEach(makeAnimalSpeak);
// Buddy 汪汪叫
// Whiskers 喵喵叫
```

```swift !! swift
// Swift 多态
class Cat: Animal {
    override func speak() {
        print("\(name) 喵喵叫")
    }
}

func makeAnimalSpeak(_ animal: Animal) {
    animal.speak()
}

let animals: [Animal] = [
    Dog(name: "Buddy", breed: "金毛"),
    Cat(name: "Whiskers")
]

for animal in animals {
    makeAnimalSpeak(animal)
}
// Buddy 汪汪叫
// Whiskers 喵喵叫
```
</UniversalEditor>

## 值类型与引用类型

这是 Swift 和 JavaScript 之间的根本差异。

### 引用类型（类）

<UniversalEditor title="引用类型对比" compare={true}>
```javascript !! js
// JavaScript：所有对象都是引用类型
class Person {
    constructor(name) {
        this.name = name;
    }
}

const person1 = new Person("Alice");
const person2 = person1; // 引用复制
person2.name = "Bob";
console.log(person1.name); // "Bob"（共享引用）
console.log(person2.name); // "Bob"
console.log(person1 === person2); // true（相同引用）
```

```swift !! swift
// Swift：类是引用类型
class Person {
    var name: String
    
    init(name: String) {
        self.name = name
    }
}

let person1 = Person(name: "Alice")
let person2 = person1 // 引用复制
person2.name = "Bob"
print(person1.name) // "Bob"（共享引用）
print(person2.name) // "Bob"
print(person1 === person2) // true（相同引用）
```
</UniversalEditor>

### 值类型（结构体）

<UniversalEditor title="值类型对比" compare={true}>
```javascript !! js
// JavaScript：没有真正的值类型，但可以用 Object.assign 模拟
const point1 = { x: 1, y: 2 };
const point2 = Object.assign({}, point1); // 浅复制
point2.x = 3;
console.log(point1.x); // 1（原对象未改变）
console.log(point2.x); // 3
console.log(point1 === point2); // false（不同对象）
```

```swift !! swift
// Swift：结构体是值类型
struct Point {
    var x: Int
    var y: Int
}

var point1 = Point(x: 1, y: 2)
var point2 = point1 // 值复制
point2.x = 3
print(point1.x) // 1（原对象未改变）
print(point2.x) // 3
print(point1 == point2) // false（不同值）
```
</UniversalEditor>

## 协议（接口）

Swift 协议类似于 JavaScript 接口，但功能更强大。

<UniversalEditor title="协议对比" compare={true}>
```javascript !! js
// JavaScript：没有内置接口，但可以使用鸭子类型
class Drawable {
    draw() {
        throw new Error("draw() 必须被实现");
    }
}

class Circle {
    constructor(radius) {
        this.radius = radius;
    }
    draw() {
        console.log(`绘制半径为 ${this.radius} 的圆`);
    }
}

class Square {
    constructor(side) {
        this.side = side;
    }
    draw() {
        console.log(`绘制边长为 ${this.side} 的正方形`);
    }
}

function drawShape(shape) {
    if (typeof shape.draw === 'function') {
        shape.draw();
    }
}

drawShape(new Circle(5));
drawShape(new Square(4));
```

```swift !! swift
// Swift：带显式遵循的协议
protocol Drawable {
    func draw()
}

class Circle: Drawable {
    var radius: Double
    
    init(radius: Double) {
        self.radius = radius
    }
    
    func draw() {
        print("绘制半径为 \(radius) 的圆")
    }
}

struct Square: Drawable {
    var side: Double
    
    func draw() {
        print("绘制边长为 \(side) 的正方形")
    }
}

func drawShape(_ shape: Drawable) {
    shape.draw()
}

drawShape(Circle(radius: 5))
drawShape(Square(side: 4))
```
</UniversalEditor>

## 高级特性

### 属性包装器和计算属性

<UniversalEditor title="高级属性" compare={true}>
```javascript !! js
// JavaScript：getter 和 setter
class BankAccount {
    constructor(balance) {
        this._balance = balance;
    }
    
    get balance() {
        return this._balance;
    }
    
    set balance(value) {
        if (value < 0) {
            throw new Error("余额不能为负数");
        }
        this._balance = value;
    }
}

const account = new BankAccount(1000);
console.log(account.balance); // 1000
account.balance = 1500; // OK
// account.balance = -100; // 错误
```

```swift !! swift
// Swift：带属性观察器的计算属性
class BankAccount {
    private var _balance: Double = 0
    
    var balance: Double {
        get {
            return _balance
        }
        set {
            if newValue < 0 {
                fatalError("余额不能为负数")
            }
            _balance = newValue
        }
    }
    
    // 属性观察器
    var accountNumber: String = "" {
        didSet {
            print("账号从 \(oldValue) 改为 \(accountNumber)")
        }
    }
}

let account = BankAccount()
account.balance = 1000
print(account.balance) // 1000
account.balance = 1500 // OK
// account.balance = -100 // 致命错误
```
</UniversalEditor>

### 静态和类方法

<UniversalEditor title="静态和类方法" compare={true}>
```javascript !! js
// JavaScript：静态方法
class MathUtils {
    static add(a, b) {
        return a + b;
    }
    
    static multiply(a, b) {
        return a * b;
    }
    
    static PI = 3.14159;
}

console.log(MathUtils.add(5, 3)); // 8
console.log(MathUtils.PI); // 3.14159
```

```swift !! swift
// Swift：静态和类方法
struct MathUtils {
    static func add(_ a: Int, _ b: Int) -> Int {
        return a + b
    }
    
    static func multiply(_ a: Int, _ b: Int) -> Int {
        return a * b
    }
    
    static let PI = 3.14159
}

class Calculator {
    class func add(_ a: Int, _ b: Int) -> Int {
        return a + b
    }
    
    static func multiply(_ a: Int, _ b: Int) -> Int {
        return a * b
    }
}

print(MathUtils.add(5, 3)) // 8
print(MathUtils.PI) // 3.14159
print(Calculator.add(5, 3)) // 8
```
</UniversalEditor>

## 练习题

### 练习 1：创建学生管理系统

<UniversalEditor title="练习 1：学生管理" compare={true}>
```javascript !! js
// JavaScript 解答
class Student {
    constructor(name, id, grades = []) {
        this.name = name;
        this.id = id;
        this.grades = grades;
    }
    
    addGrade(grade) {
        if (grade >= 0 && grade <= 100) {
            this.grades.push(grade);
        }
    }
    
    get average() {
        if (this.grades.length === 0) return 0;
        return this.grades.reduce((sum, grade) => sum + grade, 0) / this.grades.length;
    }
    
    get letterGrade() {
        const avg = this.average;
        if (avg >= 90) return 'A';
        if (avg >= 80) return 'B';
        if (avg >= 70) return 'C';
        if (avg >= 60) return 'D';
        return 'F';
    }
}

const student = new Student("Alice", "12345");
student.addGrade(85);
student.addGrade(92);
student.addGrade(78);
console.log(`${student.name}: ${student.average.toFixed(1)} (${student.letterGrade})`);
```

```swift !! swift
// Swift 解答
struct Student {
    let name: String
    let id: String
    private var grades: [Double] = []
    
    init(name: String, id: String) {
        self.name = name
        self.id = id
    }
    
    mutating func addGrade(_ grade: Double) {
        if grade >= 0 && grade <= 100 {
            grades.append(grade)
        }
    }
    
    var average: Double {
        if grades.isEmpty { return 0 }
        return grades.reduce(0, +) / Double(grades.count)
    }
    
    var letterGrade: String {
        let avg = average
        switch avg {
        case 90...:
            return "A"
        case 80..<90:
            return "B"
        case 70..<80:
            return "C"
        case 60..<70:
            return "D"
        default:
            return "F"
        }
    }
}

var student = Student(name: "Alice", id: "12345")
student.addGrade(85)
student.addGrade(92)
student.addGrade(78)
print("\(student.name): \(String(format: "%.1f", student.average)) (\(student.letterGrade))")
```
</UniversalEditor>

### 练习 2：实现形状层次结构

<UniversalEditor title="练习 2：形状层次结构" compare={true}>
```javascript !! js
// JavaScript 解答
class Shape {
    constructor(color) {
        this.color = color;
    }
    
    area() {
        throw new Error("area() 必须被实现");
    }
    
    describe() {
        console.log(`一个 ${this.color} 颜色的形状，面积为 ${this.area()}`);
    }
}

class Circle extends Shape {
    constructor(color, radius) {
        super(color);
        this.radius = radius;
    }
    
    area() {
        return Math.PI * this.radius * this.radius;
    }
}

class Rectangle extends Shape {
    constructor(color, width, height) {
        super(color);
        this.width = width;
        this.height = height;
    }
    
    area() {
        return this.width * this.height;
    }
}

const shapes = [
    new Circle("红色", 5),
    new Rectangle("蓝色", 4, 6)
];

shapes.forEach(shape => shape.describe());
```

```swift !! swift
// Swift 解答
class Shape {
    var color: String
    
    init(color: String) {
        self.color = color
    }
    
    func area() -> Double {
        fatalError("area() 必须被实现")
    }
    
    func describe() {
        print("一个 \(color) 颜色的形状，面积为 \(area())")
    }
}

class Circle: Shape {
    var radius: Double
    
    init(color: String, radius: Double) {
        self.radius = radius
        super.init(color: color)
    }
    
    override func area() -> Double {
        return Double.pi * radius * radius
    }
}

class Rectangle: Shape {
    var width: Double
    var height: Double
    
    init(color: String, width: Double, height: Double) {
        self.width = width
        self.height = height
        super.init(color: color)
    }
    
    override func area() -> Double {
        return width * height
    }
}

let shapes: [Shape] = [
    Circle(color: "红色", radius: 5),
    Rectangle(color: "蓝色", width: 4, height: 6)
]

for shape in shapes {
    shape.describe()
}
```
</UniversalEditor>

## 关键要点

### Swift OOP 优势
1. **值类型**：结构体提供值语义，防止意外突变
2. **类型安全**：强类型防止运行时错误
3. **协议**：类和结构体的灵活接口系统
4. **属性观察器**：内置的属性变化通知支持
5. **内存管理**：ARC 自动处理内存

### 与 JavaScript 的关键差异
1. **值 vs 引用**：Swift 区分值类型和引用类型
2. **继承**：只有 Swift 类支持继承
3. **可变性**：Swift 结构体需要显式的可变方法
4. **协议**：Swift 有正式的协议系统 vs JavaScript 鸭子类型
5. **内存管理**：ARC vs 垃圾回收

### 最佳实践
1. **对简单数据模型使用结构体**和值语义
2. **对需要继承的复杂对象使用类**
3. **利用协议**实现灵活接口
4. **尽可能优先使用组合而非继承**
5. **使用属性观察器**进行响应式编程
6. **考虑值类型**的线程安全性和性能

### 下一步
在下一个模块中，我们将探索 Swift 中的协议和扩展，包括协议导向编程、协议扩展，以及它们与 JavaScript 接口和混入方法的对比。 